<template>
  <div>
    <div>
      <warning-bar
        title="添加主机后，请添加授权规则，主机分组右键可新增或删除主机组"
      />
    </div>
    <el-card shadow="always">
      <div>
        <el-row :gutter="20">
          <el-col :span="4" :xs="24" :offset="0">
            <div>
              <span
                class="ml-3 w-35 text-gray-600 inline-flex items-center"
                style="font-size: 20px"
                >主机分组</span
              >
              <span class="right-11">
                <el-icon class="el-input__icon" @click="initPage"
                  ><InfoFilled /></el-icon
              ></span>
            </div>
            <el-divider />
            <div>
              <el-tree
                ref="hostGroupRef"
                :data="hostGroupTreeData"
                :props="deptDefaultProps"
                :expand-on-click-node="false"
                :filter-node-method="filterNode"
                default-expand-all
                @node-click="handleNodeClick"
                @node-contextmenu="rightClick"
              />
              <div class="rightMenu" v-show="showRightMenu">
                <ul>
                  <li>
                    <el-button type="primary" link @click="addGroup"
                      >新增同级</el-button
                    >
                  </li>
                  <li>
                    <el-button type="primary" link @click="addSonGroup"
                      >新增子级</el-button
                    >
                  </li>
                  <li>
                    <el-button type="primary" link @click="editGroup"
                      >编辑分组</el-button
                    >
                  </li>
                  <li>
                    <el-button type="danger" link @click="deleteGroup"
                      >删除分组</el-button
                    >
                  </li>
                </ul>
              </div>
            </div></el-col
          >
          <el-col :span="20" :xs="24">
            <el-row :gutter="20">
              <el-col :span="2">
                <el-button
                  plain
                  type="primary"
                  icon="plus"
                  @click="addHost"
                  size="small"
                  >添加主机</el-button
                ></el-col
              >
              <el-col :span="4">
                <el-popover v-model="deleteVisible" placement="top" width="160">
                  <p>确定要删除吗？</p>
                  <div style="text-align: right; margin-top: 8px">
                    <el-button
                      size="small"
                      type="primary"
                      link
                      @click="deleteVisible = false"
                      >取消</el-button
                    >
                    <el-button size="small" type="primary" @click="deleteHosts"
                      >确定</el-button
                    >
                  </div>
                  <template #reference>
                    <el-button
                      :disabled="!multipleSelection.length"
                      type="danger"
                      icon="delete"
                      size="small"
                      @click="deleteVisible = true"
                      >删除主机</el-button
                    >
                  </template>
                </el-popover>
              </el-col>
              <el-col :span="8">
                <el-input
                  placeholder="主机名 / IP地址模糊搜索主机"
                  v-model="searchData"
                >
                  <template #suffix>
                    <el-icon @click="initPage" style="cursor: pointer"
                      ><search
                    /></el-icon>
                  </template>
                </el-input>
              </el-col>
              <el-col :span="8">
                <el-button type="primary" size="small" @click="pushConcole"
                  >Web 终端</el-button
                ></el-col
              >
            </el-row>
            <el-row class="mt-2">
              <el-table
                style="width: 100%"
                :data="hostList"
                empty-text="暂无数据"
                tooltip-effect="dark"
                row-key="id"
                v-loading="loading"
                @selection-change="handleSelectionChange"
              >
                <el-table-column align="left" type="selection" width="55" />
                <el-table-column prop="name" label="名称" width="80" />
                <el-table-column prop="address" label="地址" width="200" />
                <el-table-column prop="port" label="端口" width="80" />
                <el-table-column prop="groupName" label="主机组" width="150" />
                <el-table-column prop="status" label="运行状态" width="80">
                  <template #default="scope">
                    <el-tag
                      class="mx-1"
                      :type="fitterStatusType(scope.row.status)"
                      effect="light"
                    >
                      {{ fitterStatusLabel(scope.row.status) }}
                    </el-tag>
                  </template>
                </el-table-column>
                <el-table-column prop="created_at" label="创建时间" width="200">
                  <template #default="scope">
                    {{ formatDate(scope.row.created_at) }}
                  </template>
                </el-table-column>
                <el-table-column fixed="right" label="操作" width="200">
                  <template #default="scope">
                    <el-button
                      link
                      type="primary"
                      size="small"
                      @click="editHost(scope.row)"
                      >编辑</el-button
                    >
                    <el-button
                      link
                      type="primary"
                      size="small"
                      @click="toWebShell(scope.row)"
                      >终端</el-button
                    >
                    <el-popover
                      v-model="deleteVisible"
                      placement="top"
                      width="160"
                    >
                      <p>确定要删除吗？</p>
                      <div style="text-align: right; margin-top: 8px">
                        <el-button
                          size="small"
                          type="primary"
                          link
                          @click="deleteVisible = false"
                          >取消</el-button
                        >
                        <el-button
                          size="small"
                          type="primary"
                          @click="deleteHost(scope.row)"
                          >确定</el-button
                        >
                      </div>
                      <template #reference>
                        <el-button
                          link
                          type="primary"
                          size="small"
                          @click="deleteVisible = true"
                          >删除</el-button
                        >
                      </template>
                    </el-popover>
                  </template>
                </el-table-column>
              </el-table>
              <div class="gva-pagination mt-2" v-if="total > 0">
                <el-pagination
                  :current-page="page"
                  :page-size="pageSize"
                  :page-sizes="[10, 30, 50, 100]"
                  :total="total"
                  layout="total, sizes, prev, pager, next, jumper"
                  @current-change="handleCurrentChange"
                  @size-change="handleSizeChange"
                />
              </div>
            </el-row>
          </el-col>
        </el-row>
      </div>
    </el-card>
    <!-- 添加编辑主机分组弹窗 -->
    <div>
      <el-dialog
        v-model="hostGroupdialogVisible"
        :title="hostGroupdialogTitle"
        width="30%"
        draggable
      >
        <el-form
          ref="hostGroupFormRef"
          :model="hostGroupForm"
          :rules="hostGroupRules"
          label-width="80px"
        >
          <el-form-item label="名称" prop="groupName">
            <el-input v-model="hostGroupForm.groupName" autocomplete="off" />
          </el-form-item>

          <el-form-item label="顺序" prop="sort">
            <el-input-number
              controls-position="right"
              v-model="hostGroupForm.sort"
              autocomplete="off"
            />
          </el-form-item>
        </el-form>
        <template #footer>
          <span class="dialog-footer">
            <el-button @click="hostGroupdialogVisible = false">取消</el-button>
            <el-button type="primary" @click="doHostGroupAddOrUpdate">
              确认
            </el-button>
          </span>
        </template>
      </el-dialog>
    </div>

    <!-- 添加删除弹窗 -->
    <div>
      <el-dialog
        v-model="dialogVisible"
        :title="dialogTitle"
        width="30%"
        draggable
      >
        <el-form
          ref="dialogForm"
          :model="form"
          :rules="rules"
          label-width="80px"
        >
          <el-form-item label="主机组" prop="hostGroup">
            <el-select
              v-model="form.cmdbHostGroupID"
              placeholder="请选择主机分组"
            >
              <el-option
                v-for="(item, index) in HostGroupList"
                :key="index"
                :label="item.groupName"
                :value="item.id"
              />
            </el-select>
          </el-form-item>
          <el-form-item label="名称" prop="name">
            <el-input v-model="form.name" autocomplete="off" />
          </el-form-item>
          <el-form-item label="使用认证" prop="useSecret">
            <el-tooltip content="是否使用认证信息中创建的连接信息">
              <el-switch
                :disabled="SecretList.length == 0"
                v-model="form.useSecret"
                :active-value="useSecret"
                :inactive-value="notUseSecret"
              />
            </el-tooltip>
            <div v-if="SecretList.length == 0">
              <span class="m-2"> 认证信息为空</span>
              <span class="m-2">
                <el-button type="primary" link @click="pushSecret"
                  >去创建</el-button
                ></span
              >
            </div>
          </el-form-item>
          <el-form-item label="IP地址" prop="address">
            <el-input v-model="form.address" />
          </el-form-item>
          <el-form-item label="端口" prop="port">
            <el-input v-model.number="form.port" autocomplete="off" />
          </el-form-item>
          <el-form-item
            label="认证信息"
            prop="hostGroup"
            v-if="form.useSecret == useSecret"
          >
            <el-select v-model="form.secretID" placeholder="请选择认证信息">
              <el-option
                v-for="(item, index) in SecretList"
                :key="index"
                :label="item.name"
                :value="item.id"
              />
            </el-select>
          </el-form-item>
          <el-form-item
            label="类型"
            prop="secretType"
            v-if="form.useSecret == notUseSecret"
          >
            <el-radio-group v-model="form.secretType" class="ml-4">
              <el-radio :label="passwordType" size="large"
                >用户名密码认证</el-radio
              >
              <el-radio :label="privateKeyType" size="large">秘钥认证</el-radio>
            </el-radio-group>
          </el-form-item>
          <el-form-item
            label="用户"
            prop="hostUserName"
            v-if="form.useSecret == notUseSecret"
          >
            <el-input
              v-model="form.hostUserName"
              autocomplete="off"
              :suffix-icon="User"
            />
          </el-form-item>
          <el-form-item
            v-if="form.secretType === 2 && form.useSecret == notUseSecret"
            label="私钥"
            prop="privateKey"
          >
            <el-input
              v-model="form.privateKey"
              autocomplete="off"
              type="textarea"
              :rows="2"
            />
          </el-form-item>
          <el-form-item
            v-if="form.secretType === 1 && form.useSecret == notUseSecret"
            label="密码"
            prop="hostPassword"
          >
            <el-input
              v-model="form.hostPassword"
              autocomplete="off"
              show-password
              type="password"
            />
          </el-form-item>
          <el-form-item
            label="协议"
            prop="protocol"
            v-if="form.useSecret == notUseSecret"
          >
            <el-select v-model="form.protocol" placeholder="请选择协议">
              <el-option
                v-for="(item, index) in protocolOpt"
                :key="index"
                :label="item.label"
                :value="item.value"
              />
            </el-select>
          </el-form-item>
          <el-form-item
            label="备注"
            prop="content"
            v-if="form.useSecret == notUseSecret"
          >
            <el-input v-model="form.content" autocomplete="off" />
          </el-form-item>
        </el-form>
        <template #footer>
          <span class="dialog-footer">
            <el-button @click="dialogVisible = false">取消</el-button>
            <el-button type="primary" @click="doAddOrUpdate"> 确认 </el-button>
          </span>
        </template>
      </el-dialog>
    </div>
  </div>
</template>

<script setup>
import WarningBar from "~/components/messageBar/warningBar.vue";
import { formatDate } from "~/utils/format";
import { InfoFilled } from "@element-plus/icons-vue";
import { useRouter } from "vue-router";
import { message } from "~/utils/utils.js";
import {
  GetHostGroupTree,
  CreateHostGroup,
  CreateSonHostGroup,
  DeleteHostGroup,
  GetPageHosts,
  GetHostGroupList,
  UpdateHostGroup,
  GetSecretList,
  CreateHost,
  DeleteHost,
  DeleteHosts,
  UpdateHost,
} from "~/api/cmdb";
import { ref } from "vue";

// 主机组相关
const hostGroupTreeData = ref([]);
const hostGroupRef = ref(null);
const deptDefaultProps = ref({
  children: "children",
  label: "groupName",
});
const initHostGroup = async () => {
  const res = await GetHostGroupTree();
  if (res) {
    // 更改groupName 增加主机数量显示
    res.forEach((item) => {
      if (item.hostNum > 0) {
        item.groupName = `${item.groupName}(${item.hostNum})`;
      }
    });
    hostGroupTreeData.value = res;
  }
  initHostGroupList();
};

// 主机组相关 el tree 右键自定义菜单
const hostGroupdialogVisible = ref(false);
const showRightMenu = ref(false);
const hostGroupdialogTitle = ref("");
const hostGroupFormRef = ref(null);
const hostGroupdialogTyle = ref("");

const hostGroupForm = ref({
  instanceID: "",
  sort: 1,
  groupName: "",
});

const hostGroupRules = ref({
  groupName: [{ required: true, message: "请输入名称", trigger: "blur" }],
});

// 右键 数据存储对象
const hostGroupRightClickData = ref({});

const rightClick = (event, data, node, json) => {
  hostGroupRightClickData.value = data;
  showRightMenu.value = false;
  let menu = document.querySelector(".rightMenu");
  menu.style.left = event.clientX + "px";
  menu.style.top = event.clientY + "px";
  showRightMenu.value = true;
  document.addEventListener("click", show);
};
const show = () => {
  showRightMenu.value = false;
};

const initHostGroupForm = () => {
  if (hostGroupFormRef.value) {
    hostGroupFormRef.value.resetFields();
  }

  hostGroupForm.value = {
    instanceID: "",
    sort: 1,
    groupName: "",
  };
};

const addGroup = () => {
  initHostGroupForm();
  hostGroupdialogVisible.value = true;
  hostGroupdialogTitle.value = "新增同级主机组";
  hostGroupdialogTyle.value = "addGroup";
};

const addSonGroup = () => {
  initHostGroupForm();
  hostGroupdialogVisible.value = true;
  hostGroupdialogTitle.value = "新增子级主机组";
  hostGroupdialogTyle.value = "addSonGroup";
};

const editGroup = () => {
  hostGroupdialogVisible.value = true;
  hostGroupdialogTitle.value = "编辑主机组";
  hostGroupdialogTyle.value = "editGroup";
  for (const key in hostGroupForm.value) {
    hostGroupForm.value[key] = hostGroupRightClickData.value[key];
  }
};

// 主机组相关 真正发起调用
const doHostGroupAddOrUpdate = () => {
  hostGroupFormRef.value.validate(async (valid) => {
    if (valid) {
      hostGroupForm.value.instanceID = hostGroupRightClickData.value.instanceID;
      switch (hostGroupdialogTyle.value) {
        case "addGroup":
          const res = await CreateHostGroup(hostGroupForm.value);
          if (res) {
            message(res);
            initHostGroup();
            hostGroupdialogVisible.value = false;
          }
          break;
        case "addSonGroup":
          const sonres = await CreateSonHostGroup(hostGroupForm.value);
          if (sonres) {
            message(sonres);
            initHostGroup();
            hostGroupdialogVisible.value = false;
          }
          break;
        case "editGroup":
          const editres = await UpdateHostGroup(hostGroupForm.value);
          if (editres) {
            message(editres);
            initHostGroup();
            hostGroupdialogVisible.value = false;
          }
          break;
      }
    }
  });
};

const deleteGroup = async () => {
  const res = await DeleteHostGroup(hostGroupRightClickData.value.instanceID);
  if (res) {
    message(res);
    initHostGroup();
  }
};

// 主机组相关 筛选节点
const filterNode = (value, data) => {
  if (!value) return true;
  return data.groupName.indexOf(value) !== -1;
};

const handleNodeClick = (row) => {
  groupID.value = row.id;
  initPage();
};

// 主机相关
// (1) 主机搜索相关
const searchData = ref("");

const hostList = ref([]);
const loading = ref(true);

// (2) 分页相关
const page = ref(1);
const total = ref(0);
const pageSize = ref(10);
const handleSizeChange = (val) => {
  pageSize.value = val;
  initPage();
};
const handleCurrentChange = (val) => {
  page.value = val;
  initPage();
};

const groupID = ref(1);
const initPage = async () => {
  const query = {
    page: page.value,
    pageSize: pageSize.value,
    keyword: searchData.value,
    groupID: groupID.value,
  };
  const res = await GetPageHosts(query);
  if (res) {
    loading.value = false;
    hostList.value = res.list;
  }
};

// （3）获取主机组列表
const HostGroupList = ref([]);
const initHostGroupList = async () => {
  const res = await GetHostGroupList();
  if (res) {
    HostGroupList.value = res;
  }
};

const SecretList = ref([]);
const initSecretList = async () => {
  const res = await GetSecretList();
  if (res) {
    SecretList.value = res;
  }
};

// 在线离线状态
const statusMap = {
  1: {
    type: "success",
    label: "在线",
  },
  2: {
    type: "danger",
    label: "离线",
  },
};

// 跳转创建认证信息
const router = useRouter();
const pushSecret = () => {
  router.push("/secret");
};
const pushConcole = () => {
  router.push("/host/webshell");
};

const fitterStatusType = (statusID) => {
  return statusMap[statusID].type;
};

const fitterStatusLabel = (statusID) => {
  return statusMap[statusID].label;
};

// 添加更新相关
const dialogForm = ref(null);
const dialogVisible = ref(false);
const dialogType = ref("add");
const dialogTitle = ref("");

const initForm = () => {
  if (dialogForm.value) {
    dialogForm.value.resetFields();
  }
  form.value = {
    name: "",
    cmdbHostGroupID: 1,
    secretID: 1,
    instanceID: "",
    useSecret: 2,
    secretType: 1,
    hostUserName: "",
    port: 22,
    address: "",
    hostPassword: "",
    privateKey: "",
    protocol: 1,
  };
};

const protocolOpt = [
  {
    value: 1,
    label: "SSH",
  },
  {
    value: 2,
    label: "RDP",
  },
];
const passwordType = 1;
const privateKeyType = 2;

const useSecret = 1;
const notUseSecret = 2;
const form = ref({
  name: "",
  cmdbHostGroupID: 1,
  secretID: 1,
  instanceID: "",
  useSecret: 2,
  secretType: 1,
  hostUserName: "",
  port: 22,
  address: "",
  hostPassword: "",
  privateKey: "",
  protocol: 1,
});
// （1） 添加主机
const addHost = () => {
  initForm();
  dialogVisible.value = true;
  dialogTitle.value = "新增主机";
  dialogType.value = "add";
};
// （2） 修改主机
const editHost = (row) => {
  dialogVisible.value = true;
  dialogTitle.value = "编辑主机";
  dialogType.value = "edit";
  for (const key in form.value) {
    form.value[key] = row[key];
  }
};

// (3) 真正执行添加或编辑动作
const doAddOrUpdate = () => {
  dialogForm.value.validate(async (valid) => {
    if (valid) {
      switch (dialogType.value) {
        case "add":
          const addRes = await CreateHost(form.value);
          if (addRes) {
            dialogVisible.value = false;
            initAll();
            message(addRes);
          }
          break;
        case "edit":
          const editRes = await UpdateHost(form.value);
          if (editRes) {
            initAll();
            dialogVisible.value = false;
            message(editRes);
          }
          break;
      }
    }
  });
};

// 删除主机相关
const multipleSelection = ref([]);
const handleSelectionChange = (val) => {
  multipleSelection.value = val;
};
const deleteVisible = ref(false);
// (1) 批量删除
const deleteHosts = async () => {
  const ids = [];
  multipleSelection.value &&
    multipleSelection.value.forEach((item) => {
      ids.push(item.instanceID);
    });
  const res = await DeleteHosts({ ids });
  if (res) {
    deleteVisible.value = false;
    initAll();
    message(res);
    if (HostGroupList.value.length === ids.length && page.value > 1) {
      page.value--;
    }
  }
};

const deleteHost = async (row) => {
  const res = await DeleteHost(row.instanceID);
  if (res) {
    message(res);
    deleteVisible.value = false;
    initAll();
  }
};

// 跳转主机终端页面
const toWebShell = (row) => {
  const url = `/host/webshell?instanceID=${row.instanceID}&name=${row.name}-${row.address}`;
  router.push(url);
};

// 校验相关
const validateIP = (rule, value, callback) => {
  if (value === "" || typeof value === "undefined" || value == null) {
    callback(new Error("请输入正确的IP地址"));
  } else {
    const reg =
      /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/;
    if (!reg.test(value) && value !== "") {
      callback(new Error("请输入正确的IP地址"));
    } else {
      callback();
    }
  }
};

const mustUint = (rule, value, callback) => {
  if (!/^[0-9]*[1-9][0-9]*$/.test(value)) {
    return callback(new Error("请输入正整数"));
  }
  return callback();
};

const rules = ref({
  name: [{ required: true, message: "请输入名称", trigger: "blur" }],
  port: [
    { required: true, message: "请输入端口", trigger: "blur" },
    { validator: mustUint, trigger: "blur", message: "端口必须为正整数" },
  ],
  address: [
    { required: true, message: "请输入IP地址", trigger: "blur" },
    { validator: validateIP, trigger: "blur", message: "请输入正确的IP地址" },
  ],
});

// 实际调用
const initAll = () => {
  initHostGroup();
  initSecretList();
  initPage();
};

initHostGroup();
initSecretList();
initPage();
</script>

<style scoped>
.rightMenu {
  position: fixed;
  z-index: 99999999;
  cursor: pointer;
  border: 1px solid #eee;
  box-shadow: 0 0.5em 1em 2px rgba(0, 0, 0, 0.1);
  border-radius: 6px;
  color: #1a1a1a;
}
.rightMenu ul {
  list-style: none;
  margin: 0;
  padding: 0;
  border-radius: 6px;
}
.rightMenu ul li {
  padding: 6px 10px;
  background: rgb(255, 255, 255);
  /* border-bottom: 1px solid #000; */
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: space-around;
}
/* .rightMenu ul li:last-child {
  border: none;
}
.rightMenu ul li:hover {
  transition: all 1s;
  background: #020e3d;
} */
</style>
